﻿//===============================================================================
// CB Stock Data Library
//===============================================================================
// Copyright © CB.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 
// OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
// WITH THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Reflection;

namespace CB.Stock.Core
{
    public interface IStockDynamicData
    {
        /// <summary>
        /// the information get time
        /// </summary>
        DateTime Time { get; }
        /// <summary>
        /// the value of the data
        /// </summary>
        /// <remarks>
        /// try to use generic one, avoid to use this as possible as you can
        /// </remarks>
        object Data { get; }

        StockDataType DataType { get; }
    }

    public interface IStockDynamicData<out T> : IStockDynamicData
    {
        /// <summary>
        /// the generic value of the data
        /// </summary>
        new T Data { get; }
    }

    public class DefaultDynamicData<T> : IStockDynamicData<T>
    {
        private static readonly Dictionary<StockDataType, Type> DefaultDynamicDataTypesDict =
            new Dictionary<StockDataType, Type>();

        static DefaultDynamicData()
        {
            var baseType = typeof(DefaultDynamicData<>);
            foreach (var t in typeof(StockDataType).GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public))
            {
                var type = (StockDataType) t.GetValue(null);
                var actualType = baseType.MakeGenericType(StockDataValueTypeAttribute.GetStaockDataType(type));
                DefaultDynamicDataTypesDict[type] = actualType;
            }
        }

        public static Type GetDefaultDynamicDataType(StockDataType stockDataType)
        {
            return DefaultDynamicDataTypesDict[stockDataType];
        }

        public DefaultDynamicData(StockDataType dataType, T value)
            : this(dataType, value, DateTime.Now)
        {

        }

        public DefaultDynamicData(StockDataType dataType, T value, DateTime time)
        {
            Time = time;
            _data = value;
            DataType = dataType;
        }

        #region Implementation of IStockDynamicData

        /// <summary>
        /// the information get time
        /// </summary>
        public DateTime Time { get; private set; }

        private T _data;
        /// <summary>
        /// the generic value of the data
        /// </summary>
        public T Data
        {
            get
            {
                return _data;
            }
            protected set
            {
                _data = value;
            }
        }

        /// <summary>
        /// the value of the data
        /// </summary>
        /// <remarks>
        /// try to use generic one, avoid to use this as possible as you can
        /// </remarks>
        object IStockDynamicData.Data
        {
            get { return Data; }
        }

        public StockDataType DataType { get; private set; }

        #endregion
    }
}
